﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GzipManagerPro.UI.Utility
{
    /// <summary>
    /// Standard .NET FileSystemInfos are always not equal to each other.
    /// When we try to refresh a directory, our controls can't match up new
    /// files with existing files. They are also sealed so we can't just subclass them.
    /// This class is a wrapper around a FileSystemInfo that simply provides
    /// equality.
    /// </summary>
    public class CustomFileSystemInfo : IEquatable<CustomFileSystemInfo>
    {
        public CustomFileSystemInfo(FileSystemInfo fileSystemInfo)
        {
            if (fileSystemInfo == null) throw new ArgumentNullException("fileSystemInfo");
            this.info = fileSystemInfo;
        }

        public bool IsDirectory { get { return this.AsDirectory != null; } }

        public DirectoryInfo AsDirectory { get { return info as DirectoryInfo; } }
        public FileInfo AsFile { get { return info as FileInfo; } }

        public FileSystemInfo Info
        {
            get { return this.info; }
        }
        private readonly FileSystemInfo info;

        public string Name
        {
            get { return info.Name; }
        }

        public string Extension
        {
            get { return info.Extension; }
        }

        public DateTime CreationTime
        {
            get { return info.CreationTime; }
        }

        public DateTime LastWriteTime
        {
            get { return info.LastWriteTime; }
        }

        public string FullName
        {
            get { return info.FullName; }
        }

        public FileAttributes Attributes
        {
            get { return info.Attributes; }
        }

        public long Length
        {
            get { return this.AsFile.Length; }
        }

        public IEnumerable GetFileSystemInfos()
        {
            ArrayList children = new ArrayList();
            if (this.IsDirectory)
            {
                // Checking if the directory is drive:
                try
                {
                    DriveInfo drive = new DriveInfo(this.Name);
                    if (!drive.IsReady)
                        return children;
                }
                catch
                {
                }
                foreach (FileSystemInfo x in this.AsDirectory.GetFileSystemInfos())
                    children.Add(new CustomFileSystemInfo(x));
            }

            children.Sort(new FileDirectoryComparer());

            return children;
        }

        // Two file system objects are equal if they point to the same file system path

        public bool Equals(CustomFileSystemInfo other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return Equals(other.info.FullName, this.info.FullName);
        }
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof(CustomFileSystemInfo)) return false;
            return Equals((CustomFileSystemInfo)obj);
        }
        public override int GetHashCode()
        {
            return (this.info != null ? this.info.FullName.GetHashCode() : 0);
        }
        public static bool operator ==(CustomFileSystemInfo left, CustomFileSystemInfo right)
        {
            return Equals(left, right);
        }
        public static bool operator !=(CustomFileSystemInfo left, CustomFileSystemInfo right)
        {
            return !Equals(left, right);
        }
    }

    public class FileDirectoryComparer: IComparer
    {
        public int Compare(object x, object y)
        {
            CustomFileSystemInfo first, second;

            first = (CustomFileSystemInfo)x;
            second = (CustomFileSystemInfo)y;

            DirectoryInfo firstDirectory, secondDirectory;
            firstDirectory = first.AsDirectory;
            secondDirectory = second.AsDirectory;

            if (firstDirectory != null && secondDirectory == null)
                return -1;

            if (secondDirectory != null && firstDirectory == null)
                return 1;

            if (secondDirectory != null && firstDirectory != null)
                return string.Compare(firstDirectory.Name, secondDirectory.Name);

            return string.Compare(first.Name, second.Name);
        }
    }
}
